package base

import (
	"bytes"
	"database/sql"
	"errors"
	"fmt"
	"os"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/leekchan/accounting"
)

//IsBlank 判断值是否为空
func IsBlank(value reflect.Value) bool {
	return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface())
}

//ToString interface 转化为string
func ToString(value interface{}) string {
	switch tVal := value.(type) {
	case float32, float64:
		return fmt.Sprintf("%g", tVal)
	case int, int32, int64:
		return fmt.Sprintf("%d", tVal)
	case bool:
		return fmt.Sprintf("%t", tVal)
	case []byte:
		return fmt.Sprintf("%s", string(tVal))
	case time.Time:
		t := value.(time.Time)
		return fmt.Sprintf("%d", t.Unix())
	case string:
		return fmt.Sprintf("%s", tVal)
	default:
		return fmt.Sprintf("%v", tVal)
	}
}

//ToInterfaceSlice []string转[]interface{}
func ToInterfaceSlice(vals []string) []interface{} {
	vLen := len(vals)
	rVals := make([]interface{}, vLen, vLen)
	for i, val := range vals {
		rVals[i] = val
	}
	return rVals
}

//GetColumns 获取Sql执行之后的列值
func GetColumns(rows *sql.Rows) ([]string, error) {
	cols, err := rows.Columns()
	if err != nil {
		return nil, err
	}
	cLen := len(cols)
	for i := 0; i < cLen; i++ {
		cols[i] = strings.ToUpper(cols[i])
	}
	return cols, nil
}

//FormatValue 按照度量值的单位转换值，并格式化为字符串
func FormatValue(unitBase int, val interface{}) interface{} {
	if val == nil {
		return nil
	}
	ac := accounting.Accounting{Symbol: "", Precision: 2}
	if val2, b := val.(float64); b {
		val2 = val2 / float64(unitBase)
		return ac.FormatMoney(val2)
	} else if val2, b := val.(float32); b {
		val2 = val2 / float32(unitBase)
		return ac.FormatMoney(val2)
	} else if val2, b := val.(int64); b {
		val2 = val2 / int64(unitBase)
		return ac.FormatMoney(val2)
	} else if val2, b := val.(int32); b {
		val2 = val2 / int32(unitBase)
		return ac.FormatMoney(val2)
	} else if val2, b := val.(string); b {
		if IsDecimals(val2) {
			fVal, _ := strconv.ParseFloat(val2, 64)
			fVal2 := fVal / float64(unitBase)
			return ac.FormatMoney(fVal2)
		}
	}
	return val
}

func ToFloat64(val interface{}) *float64 {
	if val == nil {
		return nil
	}
	var retVal float64
	if val2, b := val.(float64); b {
		retVal = val2
	} else if val2, b := val.(float32); b {
		retVal = float64(val2)
	} else if val2, b := val.(int64); b {
		retVal = float64(val2)
	} else if val2, b := val.(int32); b {
		retVal = float64(val2)
	} else if val2, b := val.(string); b {
		retVal, _ = strconv.ParseFloat(val2, 64)
	}
	return &retVal
}

//IsDecimals 是否为小数
func IsDecimals(str ...string) bool {
	var b bool
	for _, s := range str {
		s2 := s
		if strings.HasPrefix(s, "-") {
			s2 = string(([]byte(s))[1:])
		}
		b, _ = regexp.MatchString("^\\d+\\.[0-9]+$", s2)
		if false == b {
			return b
		}
	}
	return b
}

//ToMap 转换查询结果为map
func ToMap(columns []string, row []sql.NullString) map[string]interface{} {
	dataMap := make(map[string]interface{})
	for i, col := range columns {
		if row[i].Valid {
			dataMap[col] = row[i].String
		} else {
			dataMap[col] = nil
		}
	}
	return dataMap
}

//IsInSlice 判断项目是否在切片中
func IsInSlice(arrs []string, item string) bool {
	for _, a := range arrs {
		if a == item {
			return true
		}
	}
	return false
}

//IsInSliceForInt 判断项目是否在切片中
func IsInSliceForInt(arrs []int, item int) bool {
	for _, a := range arrs {
		if a == item {
			return true
		}
	}
	return false
}

//ParseWhereCause 解析where条件
func ParseWhereCause(whereCauses []WhereCause) (whereStr string, paramVals []interface{}, err error) {
	if whereCauses == nil || len(whereCauses) == 0 {
		return "", nil, nil
	}
	var whereBuf bytes.Buffer
	paramVals = make([]interface{}, 0, 10)
	for i, cause := range whereCauses {
		whereBuf.WriteString("(")
		for j, item := range cause.WhereItems {
			itemWhere, vals, err := parseWhereItem(&item)
			if err != nil {
				return "", nil, err
			}
			whereBuf.WriteString(itemWhere)
			if l := len(cause.WhereItems); j < l-1 {
				whereBuf.WriteString(" ")
				whereBuf.WriteString(cause.RelationSign.String())
				whereBuf.WriteString(" ")
			}
			for _, val := range vals {
				paramVals = append(paramVals, val)
			}
		}
		whereBuf.WriteString(")")
		if l := len(whereCauses); i < l-1 {
			whereBuf.WriteString(" AND ")
		}
	}
	whereStr = whereBuf.String()
	return
}

//parseWhereItem 解析WhereItem
func parseWhereItem(item *WhereItem) (string, []interface{}, error) {
	var buf bytes.Buffer
	buf.WriteString(item.FieldName)
	itemVals := item.FieldValues
	vals := make([]interface{}, 0, 10)
	switch item.Operator {
	case "like":
		buf.WriteString(" like ?")
		vals = append(vals, "%"+itemVals+"%")
	case "leftlike":
		buf.WriteString(" like ?")
		vals = append(vals, itemVals+"%")
	case "rightlike":
		buf.WriteString(" like ?")
		vals = append(vals, "%"+itemVals)
	case "notlike":
		buf.WriteString(" not like ?")
		vals = append(vals, "%"+itemVals+"%")
	case "in":
		buf.WriteString(" in (")
		items := strings.Split(itemVals, ",")
		for _, item := range items {
			buf.WriteString("?,")
			vals = append(vals, item)
		}
		if l := buf.Len(); l > 0 {
			buf.Truncate(l - 1)
		}
		buf.WriteString(")")
	case "notin":
		buf.WriteString(" not in (")
		items := strings.Split(itemVals, ",")
		for _, item := range items {
			buf.WriteString("?,")
			vals = append(vals, item)
		}
		if l := buf.Len(); l > 0 {
			buf.Truncate(l - 1)
		}
		buf.WriteString(")")
	case "between":
		buf.WriteString(" between ? and ?")
		vals2 := strings.Split(itemVals, ",")
		if l := len(vals2); l < 2 {
			errInfo := fmt.Sprintf("列%s的段值参数必须提供以逗号隔开的两个值！", item.FieldName)
			return "", nil, errors.New(errInfo)
		}
		vals = append(vals, vals2[0])
		vals = append(vals, vals2[1])
	case "null":
		buf.WriteString(" is null ")
	case "empty":
		buf.WriteString(" in (null,?) ")
		vals = append(vals, "")
	default:
		buf.WriteString(" ")
		buf.WriteString(item.Operator)
		buf.WriteString(" ? ")
		vals = append(vals, itemVals)
	}
	return buf.String(), vals, nil
}

//Exists 路径是否存在
func Exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}
